
#include "PipelinePlayer.h"

using namespace ttg;
using namespace ttg::extras;
using namespace ttg::services;
using namespace ttg::pipeline;

#ifdef TTG_PL_VISUALIZER

//----------------------
//--- PipelinePlayer ---
//----------------------

ttg_internal::pipeline::PipelineInfo *PipelinePlayer::createInfo(std::list<XMLTree *>::iterator &curit)
{
	ttg_internal::pipeline::PipelineInfo *res = NULL;
	XMLTree &t = (*curit)->getSubXMLTree();
	if ((res = ttg_internal::pipeline::PipelineInfo::create(t)) == NULL)
	{
		return NULL;
	}
	else
		return res;
}

PipelinePlayer::PipelinePlayer(const char *filename)
{
	//Building XMLTree.
	xml.assign(XMLTree::XML_RO, filename);
	if (!xml.openSection("Log"))
		throw Error(Error::LOCAL, "PipelinePlayer", "PipelinePlayer",
					"Cannot find \"log\" section");
	//Creating list with states.
	structures::Dictionary<XMLTree> *ss = xml.getSubSections();
	ttg::structures::EnumerableCollection<XMLTree *> *ec = ss->removeAll();
	this->states = new std::list<XMLTree *>(ec->toList());
	SAFE_DELETE(ss);
	SAFE_DELETE(ec);
	this->nextit = states->begin();
	//Setting current frame.
	this->currentframe = 0;
	//Loading PipelineInfo.
	if (!this->states->empty())
	{
		if ((this->curpl = createInfo(nextit)) == NULL)
		{
			delete states;
			throw Error(Error::LOCAL, "PipelinePlayer", "PipelinePlayer",
						"Cannot create PipelineInfo");
		}
		nextit++;
	}
	else
		this->curpl = NULL;
	//Setting current time.
	this->t_start = ServiceBase::_Timer().getMilliSeconds();
	this->isStarted = true;
	this->ID = this->addAvatar("PIPELINE_UPDATE");
}

void PipelinePlayer::shift(int framecount)
{
	if (curpl == NULL)
		return;
	int nf = std::min<int>(std::max<int>((int)currentframe + framecount, 0), (int)this->getCount() - 1);
	framecount = nf - (int)this->currentframe;
	while (framecount > 0)
	{
		framecount--;
		this->nextit++;
	}
	while (framecount < 0)
	{
		framecount++;
		this->nextit--;
	}
	this->currentframe = nf;
	SAFE_DELETE(curpl);
	if ((curpl = createInfo(--nextit)) == NULL)
		throw Error(Error::LOCAL, "PipelinePlayer", "PipelinePlayer",
					"Cannot create PipelineInfo");
	nextit++;
	this->sendEvent(ID, curpl);
	this->t_start = ServiceBase::_Timer().getMilliSeconds();
}

void PipelinePlayer::update()
{
	if (this->isStarted && curpl != NULL)
	{
		double dt = ServiceBase::_Timer().getMilliSeconds() - t_start;
		bool shouldUpdate = false;
		while (dt > curpl->getFrameTime() && nextit != states->end())
		{
			shouldUpdate = true;
			dt -= curpl->getFrameTime();
			delete curpl;
			if ((curpl = createInfo(nextit)) == NULL)
				throw Error(Error::LOCAL, "PipelinePlayer", "update",
							"Cannot create PipelineInfo");
			currentframe = min(currentframe + 1, this->getCount() - 1);
			nextit++;
		}
		if (shouldUpdate)
		{
			this->sendEvent(ID, curpl);
			t_start = ServiceBase::_Timer().getMilliSeconds();
		}
	}
}

PipelinePlayer::~PipelinePlayer()
{
	SAFE_DELETE(curpl);
	states->clear();
}

#endif
